import db
import KBEDebug as log
import KBEngine
import time
import math
import random


class GroupMemberTable:
    def __init__(self, table_name):
        self.table_name = table_name
        self.tb = db.DBTable(table_name)
        # 所属村子id
        self.tb.setFiled('groupId', db.INT32())
        # 玩家id
        self.tb.setFiled('playerId', db.UINT32())
        # 头像url
        self.tb.setFiled('headImgUrl', db.UNICODE(256))
        # 名称
        self.tb.setFiled('nickName', db.UNICODE(128))
        # 最新的抓到鹅的时间，用于判断今天是否已抓
        self.tb.setFiled('catchTime', db.UINT32())
        # 总的抓捕次数
        self.tb.setFiled(f'catchCount', db.INT32())
        # 加入村子时间
        self.tb.setFiled(f'joinTime', db.UINT32())
        # 成员类型：0-真实玩家，1-ai玩家
        self.tb.setFiled(f'playerType', db.UINT32())

    def createTable(self, success_callback):
        self.tb.exec(success_callback)


class GroupTable:
    def __init__(self, table_name):
        self.table_name = table_name
        self.tb = db.DBTable(table_name)
        self.tb.setFiled('groupId', db.INT32())
        self.tb.setFiled('groupName', db.UNICODE(128))
        self.tb.setFiled('groupDesc', db.UNICODE(128))
        # 总抓鹅次数
        self.tb.setFiled('totalCatchCount', db.INT32())
        # 成员个数
        self.tb.setFiled('groupMemberCount', db.INT32())
        # 村长Id
        self.tb.setFiled('creatorId', db.UINT32())
        # 村长微信号
        self.tb.setFiled('creatorAccount', db.UNICODE(128))
        # 村长名称
        self.tb.setFiled('creatorName', db.UNICODE(128))
        # 村子头像
        self.tb.setFiled('creatorHeadImgUrl', db.UNICODE(256))
        # 创建村子时间
        self.tb.setFiled(f'createTime', db.UINT32())

    def createTable(self, success_callback):
        self.tb.exec(success_callback)


class ILobbyGroup:

    def __init__(self):
        self.tb_memeber = GroupMemberTable('lobby_group_member')
        self.tb_group = GroupTable('lobby_group')
        self.tb_create_cnt = 2
        self.tb_memeber.createTable(self.createTableSuccess)
        self.tb_group.createTable(self.createTableSuccess)
        self.group_info = {}
        self.group_memebers = {}

    def createTableSuccess(self):
        self.tb_create_cnt -= 1
        if self.tb_create_cnt <= 0:
            pass
            # self.initAi()

    def createGroup(self, entity_call, player_id, nickname, headImgUrl, group_name, group_desc, catch_count, catch_time, creatorAccount=''):
        """
        创建村子
        """
        log.INFO_MSG(f'createGroup {player_id} {group_name} {group_desc}')

        def callback(group_lst):
            if len(group_lst) == 0:
                def callback_member(member_lst):
                    is_create_group = False
                    if len(member_lst) == 0:
                        is_create_group = True
                        self.tb_memeber.tb.addLine({
                            'groupId': self.groupId,
                            'playerId': player_id,
                            'headImgUrl': headImgUrl,
                            'nickName': nickname,
                            'catchTime': catch_time,
                            'catchCount': catch_count,
                            'joinTime': int(time.time()),
                            'playerType': 0
                        })
                    else:
                        info = member_lst[0]
                        if info['groupId'] != 0:
                            log.ERROR_MSG(f'createGroup error player in other group: {player_id}')
                            if entity_call is not None:
                                entity_call.rank.repCreateGroup(103)  # 名称已存在
                        else:
                            info['groupId'] = self.groupId
                            info['joinTime'] = int(time.time())
                            self.tb_memeber.tb.updateLine(info, f'playerId={player_id}')
                            is_create_group = True

                    if is_create_group:
                        # 无重名的村子
                        info = {
                            'groupId': self.groupId,
                            'groupName': group_name,
                            'groupDesc': group_desc,
                            'totalCatchCount': catch_count,
                            'groupMemberCount': 1,
                            'creatorId': player_id,
                            'creatorName': nickname,
                            'creatorHeadImgUrl': headImgUrl,
                            'createTime': int(time.time()),
                            'creatorAccount': creatorAccount
                        }
                        self.tb_group.tb.addLine(info)
                        
                        #self.group_info[self.groupId] = info
                        team_info = {
                            'groupId': info['groupId'],
                            'groupName': info['groupName'],
                            'groupMemberCount': info['groupMemberCount'],
                            'totalCatchCount': info['totalCatchCount']
                        }
                        self.season_ranks[info['groupId']] = team_info
                        self.season_rank_lst.append(team_info)
                        
                        if entity_call is not None:
                            entity_call.rank.reqCreateGroupSuccess(self.groupId)
                        self.groupId += 1
                self.tb_memeber.tb.loadAll(f'playerId={player_id}', callback_member)
            else:
                self.group_info[group_lst[0]['groupId']] = group_lst[0]
                if entity_call is not None:
                    entity_call.rank.repCreateGroup(100)  # 名称已存在
        self.tb_group.tb.loadAll(f'groupName=\"{group_name}\"', callback)

    def searchGroup(self, entity_call, group_id):
        """
        查找村子
        """
        if group_id >= self.groupId:
            # 没有该村子
            entity_call.rank.repSearchGroupErr(100)
            return
        if group_id in self.group_info:
            self._searchGroup(entity_call, group_id)
        else:
            def callback(group_lst):
                if len(group_lst) == 0:
                    entity_call.rank.repSearchGroupErr(100)
                else:
                    self.group_info[group_lst[0]['groupId']] = group_lst[0]
                    self._searchGroup(entity_call, group_id)
            self.tb_group.tb.loadAll(f'groupId={group_id}', callback)

    def _searchGroup(self, entity_call, group_id):
        info = self.group_info[group_id]
        entity_call.rank.repSearchGroup(info['creatorId'], info['groupId'], info['groupName'], info['groupMemberCount'], info['totalCatchCount'], info['creatorName'], info['creatorAccount'])

    def joinGroup(self, entity_call, group_id, player_id, catch_count, head_img_url, nickname, catch_time):
        """加入村子"""
        log.INFO_MSG(f'加入村子信息:groupId:{group_id}, playerId:{player_id}, catchCount:{catch_count}, nickname:{nickname}, catchtime:{catch_time}')

        # 判断是否已经加入了村子
        def callback_member(member_lst):
            is_new = False
            if len(member_lst) == 0:
                is_new = True
            else:
                db_group_id = member_lst[0]['groupId']
                if db_group_id == group_id:
                    if entity_call is not None:
                        entity_call.rank.repJoinGroupErr(102)  # 已加入村子
                elif db_group_id == 0:  # 之前退出过村子
                    member_lst[0]['groupId'] = group_id
                else:
                    if entity_call is not None:
                        entity_call.rank.repJoinGroupErr(103)  # 已加入其他村子

            if group_id not in self.group_info:
                def callback(group_lst):
                    if len(group_lst) == 0:
                        # 没有该村子
                        if entity_call is not None:
                            entity_call.rank.repJoinGroupErr(101)
                    else:
                        self.group_info[group_lst[0]['groupId']] = group_lst[0]
                        self._joinGroup(is_new, entity_call, group_id, player_id, catch_count, head_img_url, nickname, catch_time)
                self.tb_group.tb.loadAll(f'groupId={group_id}', callback)
            else:
                self._joinGroup(is_new, entity_call, group_id, player_id, catch_count, head_img_url, nickname, catch_time)

        self.tb_memeber.tb.loadAll(f'playerId={player_id}', callback_member)

    def _joinGroup(self, is_new, entity_call, group_id, player_id, catch_count, head_img_url, nickname, catch_time):
        info = self.group_info[group_id]
        info['totalCatchCount'] += catch_count
        info['groupMemberCount'] += 1
        self.tb_group.tb.updateLine(info, f'groupId={group_id}')
        if entity_call is not None:
            entity_call.rank.joinGroupSuccess(group_id)
        member_info = {
            'groupId': group_id,
            'playerId': player_id,
            'headImgUrl': head_img_url,
            'nickName': nickname,
            'catchTime': catch_time,
            'catchCount': catch_count,
            'joinTime': int(time.time()),
            'playerType': 0
        }
        if is_new:
            self.tb_memeber.tb.addLine(member_info)
        else:
            # 重新加入村子
            self.tb_memeber.tb.updateLine(member_info, f'playerId={player_id}')
        if group_id in self.group_info:
            self.group_info[group_id] = info
        
        if group_id in self.group_memebers:
            player_info = {
                'player_id': player_id,
                'headImgUrl': head_img_url,
                'nickName': nickname,
                'catchTime': catch_time,
                'catchCount': catch_count
            }
            memebers = self.group_memebers[group_id]['memebers'].append(player_info)
            log.DEBUG_MSG(f'player {player_id} join group {group_id}, update dictionary')

    def updateCatchCount(self, player_id, group_id, inc_catch_count):
        self.updateGroupCatchCount(player_id, group_id, inc_catch_count)
        self.updateMemberCatchCount(player_id, group_id, inc_catch_count)

    def updateGroupCatchCount(self, player_id, group_id, inc_catch_count):
        if group_id in self.group_info:
            info = self.group_info[group_id]
            info['totalCatchCount'] += inc_catch_count

            self.tb_group.tb.updateLine(info, f'groupId={group_id}')
        else:
            def callback(group_lst):
                if len(group_lst) == 0:
                    # 没有该村子
                    log.ERROR_MSG(f'updateGroupCatchCount error not found group: {player_id} {group_id}')
                else:
                    info = group_lst[0]
                    self.group_info[info['groupId']] = info
                    info['totalCatchCount'] += inc_catch_count
                    self.tb_group.tb.updateLine(info, f'groupId={group_id}')
            self.tb_group.tb.loadAll(f'groupId={group_id}', callback)

    def updateMemberCatchCount(self, player_id, group_id, inc_catch_count):

        def callback_member(member_lst):
            if len(member_lst) == 0:
                log.ERROR_MSG(f'updateMemberCatchCount not found info: {player_id} {group_id}')
            else:
                info = member_lst[0]
                info['catchCount'] += inc_catch_count
                info['catchTime'] = int(time.time())
                self.tb_memeber.tb.updateLine(info, f'playerId={player_id}')

        self.tb_memeber.tb.loadAll(f'playerId={player_id}', callback_member)

    def exitGroup(self, entity_call, player_id, group_id, catch_count):
        # 先判断玩家是否加入了该村子
        def callback_member(member_lst):
            if len(member_lst) == 0:
                entity_call.rank.repExitGroupErr(102)  # 没有加入该村子
            else:
                member_info = member_lst[0]
                if member_info['groupId'] != group_id:
                    entity_call.rank.repExitGroupErr(103)  # 退出村子和加入村子的id不一样
                    return
                # else:
                #     if int(time.time()) - member_info['joinTime'] < 24 * 60 * 60:
                #         entity_call.rank.repExitGroupErr(104)
                #         return
                if group_id not in self.group_info:
                    def callback(group_lst):
                        if len(group_lst) == 0:
                            # 没有该村子
                            entity_call.rank.repExitGroupErr(101)
                        else:
                            self.group_info[group_lst[0]['groupId']] = group_lst[0]
                            self._exitGroup(entity_call, player_id, group_id, catch_count)
                    self.tb_group.tb.loadAll(f'groupId={group_id}', callback)
                else:
                    self._exitGroup(entity_call, player_id, group_id, catch_count)
        self.tb_memeber.tb.loadAll(f'playerId={player_id} and groupId={group_id}', callback_member)

    def _exitGroup(self, entity_call, player_id, group_id, catch_count):
        info = self.group_info[group_id]
        if info['creatorId'] == player_id:
        #     entity_call.rank.repExitGroupErr(105)  # 村长暂时不能退出村子
        #     return
        # elif info['creatorId'] == player_id and info['groupMemberCount'] == 1:
            self._breakGroup(entity_call, group_id)
            return
        info['totalCatchCount'] -= catch_count
        info['groupMemberCount'] -= 1
        self.tb_group.tb.updateLine(info, f'groupId={group_id}')
        self.group_info[group_id] = info
        members_lst = self.group_memebers[group_id]['memebers']
        members = [item for item in members_lst if  not item['player_id'] == player_id]
        self.group_memebers[group_id]['memebers'] = members
        sql = f'update {self.tb_memeber.table_name} set groupId=0 where playerId={player_id};'
        KBEngine.executeRawDatabaseCommand(sql, None)
        entity_call.rank.repExitGroupErr(0)

    def _breakGroup(self, entity_call, group_id):
        # 队长选择解散队伍
        def del_group_callback(result, rows, insertid, error):
            if error:
                log.ERROR_MSG(f'del lobby_group failed: {error}')
            else:
                log.INFO_MSG(f'del lobby_group success')
        def de_member_callback(result, rows, insertid, error):
            if error:
                log.ERROR_MSG(f'clear lobby_group_member failed: {error}')
            else:
                log.INFO_MSG(f'clear lobby_group_member success')
        info = self.group_info[group_id]
        member_info = self.group_memebers[group_id]
        member_lst = member_info['memebers']
        
        def callback(result, rows, insertid, error):
            if error:
                log.ERROR_MSG(f'clear groupId failed: {error}')
            else:
                log.INFO_MSG(f'clear groupId success')
        
        sql = f'update tbl_avatar_rank set sm_groupId = 0 where sm_groupId={group_id};'
        KBEngine.executeRawDatabaseCommand(sql, callback)
        
        for member in member_lst:
            playerId = member['player_id']
            if playerId in self.online_avatars:
                #log.DEBUG_MSG(f'playerId:{playerId}')
                self.online_avatars[playerId].rank.resetGroupId()
        
        sql = f'DELETE FROM lobby_group WHERE groupId = {group_id}'
        sql2 = f'DELETE FROM lobby_group_member WHERE groupId = {group_id}'
        KBEngine.executeRawDatabaseCommand(sql, del_group_callback)
        KBEngine.executeRawDatabaseCommand(sql2, de_member_callback)
        
        self.group_memebers.pop(group_id)
        self.group_info.pop(group_id)
        self.season_ranks.pop(group_id)
        self.season_rank_lst = [item for item in self.season_rank_lst if item['groupId'] != group_id]
        entity_call.rank.repExitGroupErr(1)
    
    def loadGroupMemberInRank(self, entity_call, group_id, count_in_rank):

        cur_time = int(time.time())
        if group_id in self.group_memebers:
            info = self.group_memebers[group_id]
            if cur_time - info['lastLoadTime'] < 600:
                self.pushGroupMembersInRank(entity_call, group_id)
                return

        def callback(result, rows, insertid, error):
            if error:
                log.ERROR_MSG(f'loadGroupMemberInRank failed: {error}')
            else:
                log.DEBUG_MSG(f'loadGroupMemberInRank success {len(result)}')
                result_lst = []
                for line in result:
                    head_img_url = str(line[0], 'utf-8')
                    nickname = str(line[1], 'utf-8')
                    catch_time = int(line[2])
                    catch_count = int(line[3])
                    player_id = int(line[4])
                    item = {
                        'player_id': player_id,
                        'headImgUrl': head_img_url,
                        'nickName': nickname,
                        'catchTime': catch_time,
                        'catchCount': catch_count
                    }
                    result_lst.append(item)
                self.group_memebers[group_id] = {
                    'lastLoadTime': int(time.time()),
                    'memebers': result_lst
                }
                self.pushGroupMembersInRank(entity_call, group_id)

        sql = f'select headImgUrl, nickName, catchTime, catchCount, playerId from lobby_group_member where groupId={group_id} ORDER BY catchCount DESC limit {count_in_rank};'
        KBEngine.executeRawDatabaseCommand(sql, callback)

    def pushGroupMembersInRank(self, entity_call, group_id):
        info = self.group_memebers[group_id]
        member_lst = info['memebers']
        log.DEBUG_MSG(f'data:{member_lst}')
        total_count = len(member_lst)
        slice_num = 10
        slice_count = math.ceil(total_count / slice_num)
        log.DEBUG_MSG(f'slice_count:{slice_count}; total_count:{total_count}')
        for i in range(slice_count):
            start = i * slice_num
            end = start + slice_num
            entity_call.client.repGroupMemberInRank(member_lst[start:end], i, total_count)
        log.DEBUG_MSG('pushGroupMembersInRank')
        log.DEBUG_MSG('获取角色排行榜结束')

    def createAiMemeber(self, player_id, headImgUrl, nickname, callback):
        def callback_member(member_lst):
            if len(member_lst) == 0:
                self.tb_memeber.tb.addLine({
                    'groupId': 0,
                    'playerId': player_id,
                    'headImgUrl': headImgUrl,
                    'nickName': nickname,
                    'catchTime': 0,
                    'catchCount': 0,
                    'joinTime': int(time.time()),
                    'playerType': 1
                }, callback)
        self.tb_memeber.tb.loadAll(f'playerId={player_id}', callback_member)

    def aiPlayerJoinGroupAndCatch(self, player_id):
        def callback_member(member_lst):
            if len(member_lst) == 0:
                log.ERROR_MSG(f'aiPlayerJoinGroupAndCatch error not found member: {player_id}')
            else:
                info = member_lst[0]
                # 抓鹅
                info['catchTime'] = int(time.time())
                info['catchCount'] += 1
                if info['groupId'] == 0:
                    # 加入村子
                    max_group_id = min(self.groupId, 14 - 1)
                    rd_group_id = random.randint(5, max_group_id)
                    self.joinGroup(None, rd_group_id, player_id, info['catchCount'], info['headImgUrl'], info['nickName'], info['catchTime'])
                else:
                    self.updateCatchCount(player_id, info['groupId'], 1)
        self.tb_memeber.tb.loadAll(f'playerId={player_id}', callback_member)
        
    def searchGroupId(self, entity_call, group_id):
        """
        按照id查找村子
        """
        if group_id >= self.groupId:
            # 没有该村子
            entity_call.rank.repSearchGroupId(0, 0, '', 0, 0)
            return
        if group_id in self.group_info:
            self._searchGroupId(entity_call, group_id)
        else:
            def callback(group_lst):
                if len(group_lst) == 0:
                    entity_call.rank.repSearchGroupId(0, 0, '', 0, 0)
                else:
                    self.group_info[group_lst[0]['groupId']] = group_lst[0]
                    self._searchGroupId(entity_call, group_id)
            self.tb_group.tb.loadAll(f'groupId={group_id}', callback)
    
    def _searchGroupId(self, entity_call, group_id):
        info = self.group_info[group_id]
        entity_call.rank.repSearchGroupId(1, info['groupId'], info['groupName'], info['groupMemberCount'], info['totalCatchCount'])
        
